#include "QPerceptron.h"

#include <ctime>
#include <cstdlib>

#include "Util.h"

//#define DEBUG_LP

QPerceptron::QPerceptron(TransmitFunction * _tf,int _nin,double _lrate, int _layerId)
:Perceptron(_tf,_nin,_lrate, _layerId)
{
    v.resize(ninput);
    u.resize(ninput);
}

QPerceptron::~QPerceptron(void)
{
}

double QPerceptron::BPMultiple(int _lid)
{
#ifdef DEBUG_LP
    // LP  u = w
    return BPFactor * u[_lid];

#else //ifdef DEBUG_LP

    return BPFactor*(2*u[_lid] * input[_lid] + v[_lid]);
#endif //ifdef DEBUG_LP
}

void QPerceptron::RandomInit()
{
    for (int i = 0; i < ninput; ++i)
    {
        u[i] = (1 + (rand() % 10000)) * 1.0 / 10000;
        v[i] = (1 + (rand() % 10000)) * 1.0 / 10000;
    }
    b = (1 + (rand() % 10000)) * 1.0 / 10000;
}

double QPerceptron::GetN(std::vector<double>& _input)
{
    double ret = b;

#ifndef DEBUG_LP

    for (int i = 0; i < ninput; ++i)
    {
        ret += sqr(_input[i]) * u[i] + input[i] * v[i];
    }

#else // #ifndef DEBUG_LP

    // LP u = w
    for (int i = 0; i < ninput; ++i)
    {
        ret += _input[i] * u[i];
    }
#endif //#ifndef DEBUG_LP

    return ret;
}

double QPerceptron::Simulate(std::vector<double>& _input)
{
    input = _input;
    N = GetN(_input);
    O = tFunction->F(N);
    return O;
}

void QPerceptron::UpdateBPFactor(double t)
{
    if (postP.size() == 0)
    {
        BPFactor = -2 * tFunction->PartialF(N) * (t - O);
    } else 
    {
        BPFactor = 0;
        for (int i = 0; i <postP.size(); ++i)
        {
            BPFactor += postP[i]->BPMultiple(layerId);
        }
        BPFactor *= tFunction->PartialF(N);
    }
}

void QPerceptron::UpdateWeight()
{
    for (int i =0; i < ninput; ++i)
    {
        u[i] -= learnRate * BPFactor * sqr(input[i]);
        v[i] -= learnRate * BPFactor * input[i];
    }
    b -= learnRate * BPFactor;
}

void QPerceptron::Serialize(ostream & os)
{
    os << "QPerceptron BEGIN" << endl;
    os << "ninput " << ninput << endl;
    os << "postP.size " << postP.size() << endl;
    os << "layerId " << layerId << endl;
    os << "learnRate " << learnRate << endl;
    os << "b " << b << endl;
    os << "u.size " << u.size() << endl;
    os << "u ";
    for (int i = 0; i < u.size(); ++i)
    {
        os << u[i] << " ";
    }
    os << endl;
    os << "v.size " << v.size() << endl;
    os << "v ";
    for (int i = 0; i < v.size(); ++i)
    {
        os << v[i] << " ";
    }
    os << endl;
    os << "QPerceptron END" << endl;
}

void QPerceptron::Deserialize(istream & is)
{
}